package db

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type tableField struct {
	Name    string //字段名称
	Tye     string //数据类型
	IsKey   bool   //是否主键,true:是主键，false：不是主键，
	IsNull  bool   //是否为空,true:是为空，可以不用校验数据
	Len     int    //数据长度,0:不限制长度
	Default string //默认值
}

// 根据结构体获取数据库字段的校验规则,table:是结构体或者指针
func getTableVerifyField(table interface{}) map[string]tableField {
	fieldList := make(map[string]tableField, 0)
	TableObj := reflect.TypeOf(table)
	isCheck := false
	switch TableObj.Kind() {
	case reflect.Struct: //是结构体
		isCheck = true
	case reflect.Ptr: //是结构体指针
		TableObj = TableObj.Elem()
		isCheck = true
	}
	if !isCheck {
		return fieldList
	}
	for i := 0; i < TableObj.NumField(); i++ {
		field := TableObj.Field(i)
		_type := field.Tag.Get("field")
		p := strings.Index(_type, "(")
		if p >= 0 {
			_type = _type[0:p]
		}
		name := field.Tag.Get("json")
		if name == "" || _type == "" {
			continue
		}
		v := tableField{
			Name: name,
			Tye:  _type,
		}
		null := field.Tag.Get("Null")
		v.IsNull = true
		if null != "" {
			if strings.ToLower(null) == "no" {
				v.IsNull = false
			}
		}
		key := field.Tag.Get("Key")
		if key != "" {
			if strings.ToLower(key) == "pri" {
				v.IsKey = true
			}
		}
		len := field.Tag.Get("len")
		if len != "" {
			v.Len, _ = strconv.Atoi(len)
		}
		_default := field.Tag.Get("Default")
		if _default != "" {
			v.Default = _default
		}
		fieldList[name] = v
	}
	return fieldList
}

// 只是校验当前输入的数据，是否符合数据库字段的规则，比如长度，是否为空等
// 主要用于编辑数据
func checkEditTableFieldData(fieldList map[string]tableField, data map[string]interface{}) error {

	for k, v := range data {
		o, ok := fieldList[k]
		if !ok {
			return fmt.Errorf(" %s 在数据库不存在字段", k)
		}
		if o.IsKey {
			return fmt.Errorf("主键字段 %s 不能编辑", k)
		}
		switch vv := v.(type) {
		case string:
			if o.Len > 0 && len(vv) > o.Len {
				return fmt.Errorf("字段 %s 的长度不能超过%d,当前长度 %d", k, o.Len, len(vv))
			}
			if !o.IsNull && vv == "" {
				return fmt.Errorf("字段 %s 不能为空", k)
			}
		}
	}
	return nil
}

// 校验当前输入的数据添加到表是否满足要求表的结构要求
// 主要用于新增一条数据
func checkAddTableFieldData(fieldList map[string]tableField, data map[string]interface{}) error {

	//校验添加数据，必须所有的字段都必须有值，否则返回错误信息
	for k, v := range fieldList {
		//fmt.Println("字段:", k, ";是否关键字", v.IsKey, ";字段类型:", v.Tye, ";是否为空:", v.IsNull, ";长度限制:", v.Len, ";默认值:", v.Default)

		vv, ok := data[k]
		if v.IsKey { //如果是主键，可以不用数据
			if v.Tye == "varchar" { //是字符串，不能为空
				if !ok {
					return fmt.Errorf("主键 %s 必须存在", k)
				}

				if vv.(string) == "" {
					return fmt.Errorf("主键 %s 不能为空", k)
				}
				if v.Len > 0 && len(vv.(string)) > v.Len { //长度校验
					return fmt.Errorf("字段 %s 的长度不能超过%d,当前长度 %d", k, v.Len, len(vv.(string)))
				}
			}
			continue
		}

		if !ok { //说明数据字段不存在
			if v.IsNull { //数据可以为空，不用判断
				continue
			}
			if v.Default != "" { //有默认值可以不存在
				continue
			}
			return fmt.Errorf("这个 %s 字段数据库必须存在", k)
		}
		if !v.IsNull { //字段不为空
			switch vv.(type) {
			case string:
				if vv == "" {
					return fmt.Errorf("字段 %s 不能为空", k)
				}
			}
		}
		if v.Len > 0 {
			switch vvv := vv.(type) {
			case string:
				if len(vvv) > v.Len {
					return fmt.Errorf("字段 %s 的长度不能超过%d,当前字段: %d", k, v.Len, len(vvv))
				}
			}
		}
	}
	return nil
}
